package com.lpb.spring.lpbspring.aop.proxy;

import com.lpb.spring.lpbspring.aop.advisor.Advisor;
import com.lpb.spring.lpbspring.aop.proxy.weaving.AopProxyWeaving;
import com.lpb.spring.lpbspring.ioc.BeanDefinition;
import com.lpb.spring.lpbspring.ioc.BeanFactory;
import com.lpb.spring.lpbspring.ioc.DefaultBeanFactory;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.List;

/**
 * @ClassName CglibProxy
 * @Description TODO
 * @date 2022/12/9 01:16
 * @Version 1.0
 * @authoe linpengbo
 */
public class CglibProxy implements AopProxy, MethodInterceptor {

    private static Enhancer enhancer = new Enhancer();

    //被代理对象对应的beanname
    private String beanName;

    //被代理的目标对象
    private Object target;
    //被代理对象的所有切面集合
    private List<Advisor> advisorList;
    //对beanFactory的引用
    private BeanFactory beanFactory;

    public CglibProxy(String beanName, Object target, List<Advisor> advisorList, BeanFactory beanFactory) {
        this.beanName = beanName;
        this.target = target;
        this.advisorList = advisorList;
        this.beanFactory = beanFactory;
    }

    @Override
    public Object getProxy() throws Exception {
        return this.getProxy(target.getClass().getClassLoader());
    }

    @Override
    public Object getProxy(ClassLoader cld) throws Exception {
        Class<?> superClass = this.target.getClass();
        enhancer.setSuperclass(superClass);
        enhancer.setInterfaces(this.getClass().getInterfaces());
        enhancer.setCallback(this);
        Constructor<?> constructor = null;
        try {
            constructor = superClass.getConstructor(new Class<?>[]{});
        } catch (NoSuchMethodException | SecurityException e) {

        }
        if (constructor != null) {
            return enhancer.create();
        }
        BeanDefinition bd = ((DefaultBeanFactory) beanFactory).getBeanDefinition(beanName);
        return enhancer.create(bd.getConstructor().getParameterTypes(), bd.getConstructorArgumentValues().toArray());
    }

    /**
     * 执行代理对象的方法 真正被执行的方法，这里面要完成切面增强功能向 原方法功能的织入
     *
     * @param proxy cglib生成的代理类
     * @param method
     * @param objects
     * @param methodProxy 原方法的代理
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        return AopProxyWeaving.applyAdvisor(this.target,method,objects,this.advisorList,this.beanFactory);
    }
}
